package com.by.log.statistic;

import com.by.log.handler.StatisticCollector;
import com.by.log.entity.StatisticData;

import java.time.LocalDateTime;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

/**
 * 默认统计收集器实现
 * 用于收集方法调用统计信息，如成功率、请求量、QPS等
 */
public class DefaultStatisticCollector implements StatisticCollector {
    private final String className;
    
    // 调用计数器（按类统计）
    private final AtomicLong callCount = new AtomicLong(0);
    private final AtomicLong successCount = new AtomicLong(0);
    private final AtomicLong failCount = new AtomicLong(0);
    
    // 响应时间统计（按类统计）
    private final AtomicLong totalResponseTime = new AtomicLong(0);
    private final AtomicLong maxResponseTime = new AtomicLong(0);
    private final AtomicLong minResponseTime = new AtomicLong(Long.MAX_VALUE);
    
    // 按维度统计信息
    private final Map<String, DimensionalStatistics> dimensionalStats = new ConcurrentHashMap<>();
    
    // 每分钟统计信息
    private final Map<LocalDateTime, StatisticData> minuteStats = new ConcurrentHashMap<>();
    
    public DefaultStatisticCollector(String className) {
        this.className = className;
    }

    @Override
    public void recordCall(boolean success, long responseTime) {
        // 增加总调用次数
        callCount.incrementAndGet();
        
        // 根据成功状态增加相应计数器
        if (success) {
            successCount.incrementAndGet();
        } else {
            failCount.incrementAndGet();
        }
        
        // 累加响应时间
        totalResponseTime.addAndGet(responseTime);
        
        // 更新最大响应时间
        long currentMax = maxResponseTime.get();
        while (responseTime > currentMax) {
            if (maxResponseTime.compareAndSet(currentMax, responseTime)) {
                break;
            }
            currentMax = maxResponseTime.get();
        }
        
        // 更新最小响应时间
        long currentMin = minResponseTime.get();
        while (responseTime < currentMin) {
            if (minResponseTime.compareAndSet(currentMin, responseTime)) {
                break;
            }
            currentMin = minResponseTime.get();
        }
        
        // 记录到分钟级统计数据
        recordToMinuteStats(success, responseTime);
    }
    
    /**
     * 记录维度调用统计
     * @param dimension 维度名称
     * @param targetId 目标标识
     * @param success 是否成功
     * @param responseTime 响应时间
     */
    public void recordDimensionalCall(String dimension, String targetId, boolean success, long responseTime) {
        String key = dimension + ":" + targetId;
        DimensionalStatistics stats = dimensionalStats.computeIfAbsent(key, 
            k -> new DimensionalStatistics(dimension, targetId));
        stats.recordCall(success, responseTime);
        
        // 同时记录到总统计中
        recordCall(success, responseTime);
    }

    @Override
    public Map<String, StatisticData> collectAndReset() {
        // 创建当前统计信息
        StatisticData currentData = new StatisticData();
        currentData.setDimension("class");
        currentData.setTargetId(className);
        currentData.setPeriod(LocalDateTime.now());
        currentData.setCallCount(callCount.get());
        currentData.setSuccessCount(successCount.get());
        currentData.setFailCount(failCount.get());
        currentData.setTotalResponseTime(totalResponseTime.get());
        currentData.setMaxResponseTime(maxResponseTime.get());
        currentData.setMinResponseTime(minResponseTime.get() == Long.MAX_VALUE ? 0 : minResponseTime.get());
        
        // 重置计数器
        callCount.set(0);
        successCount.set(0);
        failCount.set(0);
        totalResponseTime.set(0);
        maxResponseTime.set(0);
        minResponseTime.set(Long.MAX_VALUE);
        
        // 返回统计信息
        Map<String, StatisticData> result = new ConcurrentHashMap<>();
        result.put(className, currentData);
        
        // 添加维度统计信息
        for (Map.Entry<String, DimensionalStatistics> entry : dimensionalStats.entrySet()) {
            DimensionalStatistics dimensionalStat = entry.getValue();
            Map<String, StatisticData> dimensionalDataMap = dimensionalStat.collectAndReset();
            result.putAll(dimensionalDataMap);
        }
        
        // 清空维度统计
        dimensionalStats.clear();
        
        return result;
    }
    
    @Override
    public Map<String, StatisticData> collect() {
        // 创建当前统计信息
        StatisticData currentData = new StatisticData();
        currentData.setDimension("class");
        currentData.setTargetId(className);
        currentData.setPeriod(LocalDateTime.now());
        currentData.setCallCount(callCount.get());
        currentData.setSuccessCount(successCount.get());
        currentData.setFailCount(failCount.get());
        currentData.setTotalResponseTime(totalResponseTime.get());
        currentData.setMaxResponseTime(maxResponseTime.get());
        currentData.setMinResponseTime(minResponseTime.get() == Long.MAX_VALUE ? 0 : minResponseTime.get());
        
        // 返回统计信息
        Map<String, StatisticData> result = new ConcurrentHashMap<>();
        result.put(className, currentData);
        
        // 添加维度统计信息
        for (Map.Entry<String, DimensionalStatistics> entry : dimensionalStats.entrySet()) {
            DimensionalStatistics dimensionalStat = entry.getValue();
            Map<String, StatisticData> dimensionalDataMap = dimensionalStat.collect();
            result.putAll(dimensionalDataMap);
        }
        
        return result;
    }
    
    /**
     * 记录到分钟级统计数据
     * @param success 是否成功
     * @param responseTime 响应时间
     */
    private void recordToMinuteStats(boolean success, long responseTime) {
        LocalDateTime currentMinute = LocalDateTime.now().withSecond(0).withNano(0);
        StatisticData data = minuteStats.computeIfAbsent(currentMinute, 
                k -> {
                    StatisticData stat = new StatisticData();
                    stat.setDimension("class");
                    stat.setTargetId(className);
                    stat.setPeriod(k);
                    stat.setCallCount(0);
                    stat.setSuccessCount(0);
                    stat.setFailCount(0);
                    stat.setTotalResponseTime(0);
                    stat.setMaxResponseTime(0);
                    stat.setMinResponseTime(Long.MAX_VALUE);
                    return stat;
                });
        data.incrementCall(success, responseTime);
    }
    
    /**
     * 获取最近一分钟的统计数据
     * @return 统计数据
     */
    public StatisticData getLastMinuteStats() {
        LocalDateTime lastMinute = LocalDateTime.now().minusMinutes(1).withSecond(0).withNano(0);
        return minuteStats.get(lastMinute);
    }
    
    /**
     * 获取QPS（每秒查询率）
     * @return QPS值
     */
    public double getQPS() {
        StatisticData lastMinuteData = getLastMinuteStats();
        if (lastMinuteData != null) {
            return lastMinuteData.getCallCount() / 60.0;
        }
        return 0.0;
    }
    
    /**
     * 获取成功率
     * @return 成功率（0-1之间的值）
     */
    public double getSuccessRate() {
        long total = callCount.get();
        if (total == 0) {
            return 0.0;
        }
        return (double) successCount.get() / total;
    }
    
    /**
     * 获取平均响应时间
     * @return 平均响应时间（毫秒）
     */
    public double getAverageResponseTime() {
        long total = callCount.get();
        if (total == 0) {
            return 0.0;
        }
        return (double) totalResponseTime.get() / total;
    }
    
    /**
     * 获取当前调用总数
     * @return 调用总数
     */
    public long getCallCount() {
        return callCount.get();
    }
    
    /**
     * 获取成功调用数
     * @return 成功调用数
     */
    public long getSuccessCount() {
        return successCount.get();
    }
    
    /**
     * 获取失败调用数
     * @return 失败调用数
     */
    public long getFailCount() {
        return failCount.get();
    }
    
    /**
     * 获取总响应时间
     * @return 总响应时间
     */
    public long getTotalResponseTime() {
        return totalResponseTime.get();
    }
    
    /**
     * 获取最大响应时间
     * @return 最大响应时间
     */
    public long getMaxResponseTime() {
        return maxResponseTime.get();
    }
    
    /**
     * 获取最小响应时间
     * @return 最小响应时间
     */
    public long getMinResponseTime() {
        long min = minResponseTime.get();
        return min == Long.MAX_VALUE ? 0 : min;
    }
    
    /**
     * 获取维度统计信息
     * @param dimension 维度名称
     * @param targetId 目标标识
     * @return 维度统计信息
     */
    public DimensionalStatistics getDimensionalStatistics(String dimension, String targetId) {
        String key = dimension + ":" + targetId;
        return dimensionalStats.get(key);
    }
    
    /**
     * 获取所有维度统计信息
     * @return 维度统计信息映射
     */
    public Map<String, DimensionalStatistics> getAllDimensionalStatistics() {
        return dimensionalStats;
    }
    
    /**
     * 维度统计内部类
     */
    public static class DimensionalStatistics {
        private final String dimension;
        private final String targetId;
        private final AtomicLong callCount = new AtomicLong(0);
        private final AtomicLong successCount = new AtomicLong(0);
        private final AtomicLong failCount = new AtomicLong(0);
        private final AtomicLong totalResponseTime = new AtomicLong(0);
        private final AtomicLong maxResponseTime = new AtomicLong(0);
        private final AtomicLong minResponseTime = new AtomicLong(Long.MAX_VALUE);
        
        public DimensionalStatistics(String dimension, String targetId) {
            this.dimension = dimension;
            this.targetId = targetId;
        }
        
        public void recordCall(boolean success, long responseTime) {
            callCount.incrementAndGet();
            
            if (success) {
                successCount.incrementAndGet();
            } else {
                failCount.incrementAndGet();
            }
            
            totalResponseTime.addAndGet(responseTime);
            
            long currentMax = maxResponseTime.get();
            while (responseTime > currentMax) {
                if (maxResponseTime.compareAndSet(currentMax, responseTime)) {
                    break;
                }
                currentMax = maxResponseTime.get();
            }
            
            long currentMin = minResponseTime.get();
            while (responseTime < currentMin) {
                if (minResponseTime.compareAndSet(currentMin, responseTime)) {
                    break;
                }
                currentMin = minResponseTime.get();
            }
        }
        
        public Map<String, StatisticData> collectAndReset() {
            StatisticData data = new StatisticData();
            data.setDimension(dimension);
            data.setTargetId(targetId);
            data.setPeriod(LocalDateTime.now());
            data.setCallCount(callCount.get());
            data.setSuccessCount(successCount.get());
            data.setFailCount(failCount.get());
            data.setTotalResponseTime(totalResponseTime.get());
            data.setMaxResponseTime(maxResponseTime.get());
            data.setMinResponseTime(minResponseTime.get() == Long.MAX_VALUE ? 0 : minResponseTime.get());
            
            // 重置计数器
            callCount.set(0);
            successCount.set(0);
            failCount.set(0);
            totalResponseTime.set(0);
            maxResponseTime.set(0);
            minResponseTime.set(Long.MAX_VALUE);
            
            Map<String, StatisticData> result = new ConcurrentHashMap<>();
            result.put(dimension + ":" + targetId, data);
            return result;
        }
        
        public Map<String, StatisticData> collect() {
            StatisticData data = new StatisticData();
            data.setDimension(dimension);
            data.setTargetId(targetId);
            data.setPeriod(LocalDateTime.now());
            data.setCallCount(callCount.get());
            data.setSuccessCount(successCount.get());
            data.setFailCount(failCount.get());
            data.setTotalResponseTime(totalResponseTime.get());
            data.setMaxResponseTime(maxResponseTime.get());
            data.setMinResponseTime(minResponseTime.get() == Long.MAX_VALUE ? 0 : minResponseTime.get());
            
            Map<String, StatisticData> result = new ConcurrentHashMap<>();
            result.put(dimension + ":" + targetId, data);
            return result;
        }
        
        public double getSuccessRate() {
            long total = callCount.get();
            if (total == 0) {
                return 0.0;
            }
            return (double) successCount.get() / total;
        }
        
        public double getAverageResponseTime() {
            long total = callCount.get();
            if (total == 0) {
                return 0.0;
            }
            return (double) totalResponseTime.get() / total;
        }
        
        public double getQPS() {
            // 简化实现，实际应该基于时间窗口计算
            return callCount.get() / 60.0;
        }
        
        public long getCallCount() {
            return callCount.get();
        }
        
        public long getSuccessCount() {
            return successCount.get();
        }
        
        public long getFailCount() {
            return failCount.get();
        }
        
        public long getTotalResponseTime() {
            return totalResponseTime.get();
        }
        
        public long getMaxResponseTime() {
            return maxResponseTime.get();
        }
        
        public long getMinResponseTime() {
            long min = minResponseTime.get();
            return min == Long.MAX_VALUE ? 0 : min;
        }
        
        public String getDimension() {
            return dimension;
        }
        
        public String getTargetId() {
            return targetId;
        }
    }
}